package tenumn.energytech.registrys.machine;

import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.EnergyStorage;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.RecipeWrapper;
import org.jetbrains.annotations.Nullable;
import tenumn.energytech.registrys.RecipeRegistry;
import tenumn.energytech.registrys.recipe.OneToTwoRecipe;

import javax.annotation.Nonnull;
import java.util.concurrent.atomic.AtomicBoolean;

public class SmashBlockEntity extends MachineBlockEntity{
    boolean isGrinder=true;
    private final EnergyStorage energyStorage;
    private final int energyReducePreTick=10;
    private OneToTwoRecipe selectedRecipe;
    private int recipeProgress=0;
    private ItemStackHandler itemStackHandler=new ItemStackHandler(3){
        @Override
        public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
            return slot<1;
        }

        @Override
        protected void onContentsChanged(int slot) {
            if(level!=null)level.getChunkAt(getBlockPos()).setUnsaved(true);
            if(selectedRecipe!=null&&slot==0){
                var item=getStackInSlot(0);
                if(!selectedRecipe.input.test(item)) {
                    selectedRecipe = null;
                    recipeProgress=0;
                }
            }
        }
    };
    private final RecipeWrapper recipeWrapper=new RecipeWrapper(itemStackHandler);
    public SmashBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
        super(pType, pWorldPosition, pBlockState);
        energyStorage=new EnergyStorage(Integer.MAX_VALUE);
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
            return LazyOptional.of(() -> itemStackHandler).cast();
        if(cap== CapabilityEnergy.ENERGY)
            return LazyOptional.of(()->energyStorage).cast();
        return super.getCapability(cap, side);
    }

    @Override
    protected void saveAdditional(@Nonnull CompoundTag pTag) {
        super.saveAdditional(pTag);
        pTag.put("Item", itemStackHandler.serializeNBT());
        pTag.put("FE", energyStorage.serializeNBT());
        pTag.putInt("Progress",recipeProgress);
        if(selectedRecipe!=null)
        pTag.putString("SelectedRecipe",selectedRecipe.getId().toString());
    }

    @Override
    public void load(@Nonnull CompoundTag pTag) {
        super.load(pTag);
        energyStorage.deserializeNBT(pTag.get("FE"));
        itemStackHandler.deserializeNBT(pTag.getCompound("Item"));
        recipeProgress=pTag.getInt("Progress");
        if(pTag.contains("SelectedRecipe")&&level!=null)
            level.getRecipeManager().byKey(new ResourceLocation(pTag.getString("SelectedRecipe"))).ifPresent(recipe -> {
                selectedRecipe= (OneToTwoRecipe) recipe;
            });
    }



    @Override
    public void tick() {
        if(level instanceof ServerLevel serverLevel){
            ItemStack input= itemStackHandler.getStackInSlot(0);
            //机器有能量，输入不为空时开始匹配配方
            if(energyStorage.getEnergyStored()>energyReducePreTick&&!input.isEmpty()){
                if(selectedRecipe==null)
                    if(!matchRecipe())return;
                recipeProgress++;
                energyStorage.extractEnergy(energyReducePreTick,false);
                if(recipeProgress>=100) {
                    Pair<ItemStack, ItemStack> recipeResult = selectedRecipe.assembleRealResult(recipeWrapper,false);
                    setResult(1,recipeResult.getFirst());
                    setResult(2,recipeResult.getSecond());
                    input.shrink(1);
                    selectedRecipe=null;
                    recipeProgress=0;
                }
                serverLevel.getChunk(getBlockPos()).setUnsaved(true);
            }
        }
    }
    private void setResult(int index,ItemStack result){
        var has=itemStackHandler.getStackInSlot(index);
        if(has==ItemStack.EMPTY)itemStackHandler.setStackInSlot(index,result);
        else has.grow(result.getCount());
    }
    @Override
    public void setRemoved() {
        selectedRecipe=null;
        super.setRemoved();
    }

    public boolean matchRecipe(){
        AtomicBoolean result= new AtomicBoolean(false);
        RecipeType<? extends OneToTwoRecipe> recipeType=isGrinder?RecipeRegistry.GRINDER.recipeType:RecipeRegistry.MILLING.recipeType;
        level.getRecipeManager().getRecipeFor(recipeType,recipeWrapper,level)
                        .ifPresent(recipe->{
                            selectedRecipe= recipe;
                            result.set(true);
                        });
        return result.get();
    }
}
